package edu.gmu.atelier;

/**
 * Vector defined within some vector space.
 * @author James H. Pope
 */
public interface Vector
{
    /**
     * Gets the element at the specified position (no copy is made).
     * @param i
     * @return e at i
     */
    public Element getElement(int i);
    
    /**
     * Sets the position at i to specified element (overwriting previous). 
     * @param i
     * @param e 
     */
    public void setElement(int i, Element e);
    
    //------------------------------------------------------------------------//
    // Vector immutable operations
    //------------------------------------------------------------------------//
    
    /**
     * Adds this vector and the specified vector to produce a new vector.
     * @param v
     * @return this+v
     */
    public Vector add( Vector v );
    
    /**
     * Subtracts the specified vector fro this vector to produce a new vector.
     * @param v
     * @return this-v
     */
    public Vector sub( Vector v );
    
    /**
     * Multiplies each element in this vector by e to produce a new vector.
     * @param e
     * @return ev
     */
    public Vector mult(Element e );
    
    /**
     * Multiplies each element in this vector by each element in the
     * specified vector - thus taking the inner product of the vectors
     * to produce a single element.
     * This is also known as the "dot" product where this = u.
     * <p>
     * Real Elements are symmetric u.v = u^T*v = u*v^T, however
     * Complex Elements are not z.w = z^t*w_conj != w^T*z_conj
     * <p>
     * Therefore, when dealing with complex elements ensure order
     * is correct where "this" is on the left of specified vector v.
     * @param v
     * @return u^T.v
     */
    public Element dot(Vector v );
    
    // I believe this is mapping from norm2:V -> R, so double is fine?
    // Mathematically this is correct, but for type reasons return Element.
    /**
     * Returns the euclidean norm2 ||v||^2.  In order to get the actual 
     * length take the square root of this, e.g.  magnitude=norm2().sqrt();
     * @return norm2^2
     */
    //public double norm(); // norm
    public Element norm2(); // norm2^2, avoids sqrt as many times not needed
    
    
    /**
     * Returns new vector in same direction as this vector with norm2 of 1.
     * @return new v such that v.norm2() = 1
     */
    public Vector normalize();
    
    //------------------------------------------------------------------------//
    // Matrix operations
    //------------------------------------------------------------------------//
    /**
     * Gets the length of the vector, a.k.a. m, number components, number rows.
     * @return length
     */
    public int getLength();
    
    /**
     * Left multiplies this vector in R^N by the given matrix returning
     * a new vector in R^M.  May consider renaming "transform".
     * @param A
     * @return Ax
     */
    public Vector mult( IMatrix a ); // left multiply by A, i.e.  b = Ax
    
//    /**
//     * Produces a new square matrix of size m x m (m=this.length)
//     * where u = this, with the columns of v[0]*u, v[1]u, ..., v[m]u = u*v^T.
//     * This right multiplies this vector by the transform of v.
//     * @param v
//     * @return this*v^T
//     */
//    public Matrix mult( Vector v ); // left multiply by A, i.e.  b = Ax
    
    /**
     * Returns true is all the elements are the zero element.
     * @param
     */
    public boolean isZero();
    
    //------------------------------------------------------------------------//
    // Vector specific "row" mutator operations
    //------------------------------------------------------------------------//
    public void swap(     int fromRow, int toRow );
    public void mulTo(    int row, Element mult );
    public void mulAddTo( int fromRow, Element mult, int toRow );
    
    //------------------------------------------------------------------------//
    // Factory methods
    //------------------------------------------------------------------------//
    public Vector copy();
    public Vector copy(int start, int length);
    public void copyElements(int start, Vector subv);
    
    // Convenient location, "this" is not directly used, need to move to matrix!
    public Matrix transpose( Matrix a );
    
    //------------------------------------------------------------------------//
    // Vector specific "row" extract operations
    //------------------------------------------------------------------------//
    public Vector extract( int[] B );
    public void extractTo( int[] B, Vector b );
    
    /**
     * Determines whether this and the specified object are similar ("close
     * enough") given some tolerance e.  If e is null, then the method acts 
     * identical to the Object.equals method requiring exact equality.
     * @param obj
     * @param e
     * @return true if similar, false otherwise
     */
    public boolean similar( Object obj, Epsilon e );
}
